--[[********************************************************
	MyStore                                      v0.1

	Author:ianwatson@gmail.com

	********************************************************
	NOTICE:
		Please  feel free to modify,  compile,  redistribute
		or  otherwise use MyS code and concepts in  your  own
		works.  However if you do so, please give credit  to
		me for my work.  I only ask for a small comment line
		stating  that  this work has been used, and  nothing
		more.

		It  is a given that some Blizzard code must be  used
		as  we are working within their  sandbox.  Any  code
		that is  not  unique  to  MyS can be  assumed  to  be
		Blizzard's unless otherwise noted with the function.

		Any  oversights  on my part are simply that  and  no
		harm is intended.  If you notice an oversight please
		point  it  out to me and it will be  remedied  ASAP.
	********************************************************
	MyStore.lua
	********************************************************]]

--[[	***************************************************
		MyStore Frames:
		MyStoreFrame - Main 'background' frame
		MyS_StoreList - Store list frame
		P_MerchantFrame - Main customer view
		A_MerchantFrame - Main owner view
		MyS_MonitorFrame - Status monitor
		P_MerchantMapButton - Map Button
		*************************************************** ]]

MyS_Config = {
	useSellValue = 1,
	useSellValueMultiplier = 3,
	defaultPrice = 98765432,
	["Blacklist"] = {};
};

--[[	BEGIN Local variables ***************************** ]]

local userCursorItem = nil;
local SEND_UPDATE_INTERVAL = 0.25;
local IDLE_UPDATE_INTERVAL = 0.5;
local NEXT_UPDATE_TIME = GetTime();
local NEXT_CHAN_UPDATE = GetTime() + 5;
local ANNOUNCE_INTERVAL = 180;
local NEXT_ANNOUNCE_TIME = {
	[2] = GetTime(),
	[4] = GetTime(),
	[3] = GetTime()
};

--[[	BEGIN Hooked functions **************************** ]]

MyS_Hook = {
	chat = ChatFrame_OnEvent;
	containerItem = PickupContainerItem;
	trade = TradeFrame_SetAcceptState;
};

-- Hook the chat function to hide data from user
function ChatFrame_OnEvent(event)
	if ( event == "CHAT_MSG_WHISPER" and strsub(arg1, 1, 9) == "<MyStore>" ) then
		if ( strsub(event, 10) == "_INFORM" ) then
			-- Do nothing
		else
			MyS_Comm.msgIn(arg1, arg2);
		end
	elseif ( (event == "CHAT_MSG_CHANNEL" or event == "CHAT_MSG_GUILD" or event == "CHAT_MSG_PARTY") and strsub(arg1, 1, 9) == "<MyStore>" ) then
		-- Hide the text
	elseif ( event == "CHAT_MSG_CHANNEL_LIST" and MyS_Session.forceChanUpdate ) then
		local _,_,tradeChannel = strfind(arg1, "%[(%d+)%. Trade.+");
		if ( tradeChannel ) then
			MyS_Session.tradeChannel = tonumber(tradeChannel);
			MyS_AuxFunc.chatMessage("Trade channel updated to channel "..tradeChannel..".",1);
		else
			MyS_Session.tradeChannel = nil;
			MyS_AuxFunc.chatMessage("Trade channel not found.",1);
		end
		MyS_Session.forceChanUpdate = nil;
	else
		MyS_Hook.chat(event);
	end
end

-- Hook the container function so I know what's picked up
function PickupContainerItem(bag, slot, special)
	if ( not CursorHasItem() ) then
		userCursorItem = {
			["bag"] = bag,
			["slot"] = slot,
			["text2"] = GameTooltipTextLeft2:GetText()
		};
	else
		userCursorItem = nil;
	end
	if ( IsAltKeyDown() and A_MerchantFrame:IsVisible() and not CursorHasItem() ) then
		if ( GameTooltipTextLeft2:GetText() == "Soulbound" ) then
			UIErrorsFrame:AddMessage(ERR_TRADE_BOUND_ITEM, 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME);
			return;
		elseif ( GameTooltipTextLeft2:GetText() == "Quest Item" ) then
			UIErrorsFrame:AddMessage(ERR_TRADE_QUEST_ITEM, 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME);
			return;
		end

		-- Pick up the item
		MyS_Hook.containerItem(bag, slot);

		-- Add item
		MyS.stor.addItem(bag,slot);

		-- Put down the item
		MyS_Hook.containerItem(bag, slot);
		userCursorItem = nil;

		return;
	end
	MyS_Hook.containerItem(bag, slot, special);
end

-- Hook the trade event so I can see when a trade closes
function TradeFrame_OnHide()
	MyS.trade.endTrade();
	MyS_Hook.trade();
end

--[[	BEGIN onFoo functions ***************************** ]]

MyS_onFoo = {
	onLoad = function()
		this:RegisterEvent("UNIT_NAME_UPDATE");
		this:RegisterEvent("BAG_UPDATE");

		-- Handle channels
		this:RegisterEvent("ZONE_CHANGED_NEW_AREA");
		this:RegisterEvent("CHAT_MSG_CHANNEL");
		this:RegisterEvent("CHAT_MSG_GUILD");
		this:RegisterEvent("CHAT_MSG_PARTY");

		-- Handle Trading
		this:RegisterEvent("TRADE_SHOW");
		this:RegisterEvent("TRADE_MONEY_CHANGED");

		this:RegisterForDrag("LeftButton");
		this:RegisterForClicks("LeftButtonUp","RightButtonUp");

		if ( MG_MapButton ) then
			this:ClearAllPoints();
			this:SetPoint("RIGHT","MG_MapButton","LEFT",0,0);
		end

		SlashCmdList["PLAYERMERCH"] = function(msg) MyS.slashCmd(msg) end;
		SLASH_PLAYERMERCH1 = "/mystore";
		SLASH_PLAYERMERCH2 = "/mys";

		tinsert(UISpecialFrames,"MyStoreFrame");
	end;

	onEvent = function(event)
		if ( event == "VARIABLES_LOADED" ) then
			MyS_AuxFunc.chatMessage("MyStore loaded.",1);
		elseif ( event == "UNIT_NAME_UPDATE" and UnitName("player") ~= UNKNOWNOBJECT and not MyS_Session.user ) then
			MyS_Session.initialize();
		elseif ( not MyS_Session.user ) then
			return;
		elseif ( event == "ZONE_CHANGED_NEW_AREA" ) then
			MyS_AuxFunc.chatMessage("New zone area event.",1);
			MyS_Session.handleZone();
			return;
		elseif ( event == "BAG_UPDATE" ) then
			MyS.stor.checkData();
			MyS.stor.checkData(1);

		-- Chat Events
		elseif ( event == "CHAT_MSG_CHANNEL" and strsub(arg1, 1, 9) == "<MyStore>" ) then
			MyS_AuxFunc.chatMessage("Chat pickup: ["..arg2.."] "..arg1.."(Trade)",1);
			MyS_Comm.publicMsgIn(arg1, arg2, 4);
		elseif ( event == "CHAT_MSG_GUILD" and strsub(arg1, 1, 9) == "<MyStore>" ) then
			MyS_AuxFunc.chatMessage("Chat pickup: ["..arg2.."] "..arg1.."(Guild)",1);
			MyS_Comm.publicMsgIn(arg1, arg2, 3);
		elseif ( event == "CHAT_MSG_PARTY" and strsub(arg1, 1, 9) == "<MyStore>" ) then
			MyS_AuxFunc.chatMessage("Chat pickup: ["..arg2.."] "..arg1.."(Party)",1);
			MyS_Comm.publicMsgIn(arg1, arg2, 2);

		-- Trade Events
		elseif ( not MyS_Session.user.open or MyS_Session.user.open == 2 ) then
			return;
		elseif ( event == "TRADE_SHOW" ) then
			MyS.trade.tradeItems();
		elseif ( event == "TRADE_MONEY_CHANGED" ) then
			MyS.trade.moneyChanged();
		end
	end;

	onUpdate = function(elapsed)
		MyS_Session.checkChannels();
		if ( GetTime() < NEXT_UPDATE_TIME ) then
			return;
		end
		local player, message = MyS_Comm.getNextOutbound();
		if ( not player ) then
			NEXT_UPDATE_TIME = GetTime() + IDLE_UPDATE_INTERVAL;
			if ( P_MerchantMonitor:IsVisible() ) then
				P_MerchantMonitorText1:SetText("Queue: ");
				P_MerchantMonitorText2:SetText("Empty");
			end
			return;
		end

		NEXT_UPDATE_TIME = GetTime() + SEND_UPDATE_INTERVAL;

		-- Send 'message' to 'player'
		if ( message and player ) then
			SendChatMessage(message, "WHISPER", DEFAULT_CHAT_FRAME.language, player);
		end

		-- Debug Monitor
		if ( P_MerchantMonitor:IsVisible() ) then
			P_MerchantMonitorText1:SetText("Queue: "..player);
			if ( MyS_Comm.COMMAND_QUEUE[player] ) then
				P_MerchantMonitorText2:SetText("T:"..getn(MyS_Comm.PLAYER_QUEUE).." C:"..getn(MyS_Comm.COMMAND_QUEUE[player]));
			else
				P_MerchantMonitorText2:SetText("T:"..getn(MyS_Comm.PLAYER_QUEUE));
			end
		end
	end;
};

--[[	BEGIN Core functions ************************* ]]

MyS = {
	version = "v0.1";

	slashCmd = function(msg)
		if ( msg == "resetpos" ) then
			MyS.bgFrame.resetPos();
		elseif ( msg == "reseticon" ) then
			MyS_MapButton.resetPos();
		elseif ( msg == "chan" ) then
			MyS_Session.forceChanUpdate = 1;
		elseif ( strfind(msg,"blacklist") ) then
			local _,_,name = strfind(msg,"blacklist (.+)");
			if ( name and name ~= "clear" ) then
				if ( MyS.storeList.blackList.isListed(name) ) then
					MyS.storeList.blackList.delete(name);
					MyS_AuxFunc.chatMessage(name.." removed from blacklist.");
				else
					MyS.storeList.blackList.add(name);
					MyS_AuxFunc.chatMessage(name.." added to blacklist.");
				end
			elseif ( name and name == "clear" ) then
				MyS_Config.Blacklist = {};
				MyS_AuxFunc.chatMessage("Blacklist cleared.");
			else
				MyS.storeList.blackList.show();
			end
		elseif ( msg == "debug" ) then
			if ( MyS_Session.user.debugmode ) then
				MyS_Session.user.debugmode = nil;
				MyS_AuxFunc.chatMessage("Debug mode off.");
			else
				MyS_Session.user.debugmode = 1;
				MyS_AuxFunc.chatMessage("Debug mode on.");
			end
		elseif ( msg == "monitor" ) then
			if ( P_MerchantMonitor:IsVisible() ) then
				P_MerchantMonitor:Hide();
			else
				P_MerchantMonitor:Show();
			end
		elseif ( strlen(msg) > 0 ) then
			MyS.cust.openStore(msg);
		else
			local chatStr = MyS.version.."\nAuthor: jason.slaughter@gmail.com\n";
			chatStr = chatStr.."/mys reseticon: Reset the mapbutton icon position\n";
			chatStr = chatStr.."/mys resetpos: reset MyStore frame position\n";
			chatStr = chatStr.."/mys chan: Force a channel scan\n";
			chatStr = chatStr.."/mys <name>: Force a store connect to <name>\n";
			chatStr = chatStr.."/mys monitor: Show/hide message queue\n";
			chatStr = chatStr.."/mys debug: Show/hide debug messages\n";
			chatStr = chatStr.."/mys blacklist: Show blacklisted stores\n";
			chatStr = chatStr.."/mys blacklist clear: Clear blacklist\n";
			chatStr = chatStr.."/mys blacklist <name>: Add/Remove <name> from blacklist";
			MyS_AuxFunc.chatMessage(chatStr);
		end
	end;

	splitLink = function(link)
		local _,_,color,q1,q2,q3,q4,name = strfind(link,"|c(%x+)|Hitem:(%d+):(%d+):(%d+):(%d+)|h%[(.+)%]|h|r");
		if ( color and q1 and q2 and q3 and q4 and name ) then
			return "!COLR!"..color.."!Q1!"..q1.."!Q2!"..q2.."!Q3!"..q3.."!Q4!"..q4.."!N!"..name;
		end
	end;

	makeLink = function(color,q1,q2,q3,q4,name)
		return "|c"..color.."|Hitem:"..q1..":"..q2..":"..q3..":"..q4.."|h["..name.."]|h|r";
	end;

	setMoneyFrames = function()
		SmallMoneyFrame_OnLoad();

		this.info = {
			UpdateFunc = function()
				return this.staticMoney;
			end,
			collapse = 1,
			showSmallerCoins = 1,
			truncateSmallCoins = nil,
		};
		this.moneyType = "STATIC";

		local frameName = this:GetName();
		getglobal(frameName.."GoldButton"):Disable();
		getglobal(frameName.."SilverButton"):Disable();
		getglobal(frameName.."CopperButton"):Disable();
		MoneyFrame_UpdateMoney();
	end;

	--[[	BEGIN Background Frame Functions ************ ]]
	bgFrame = {
		selectedTab = 1;

		onLoad = function()
			this:SetMovable(1);
			this:RegisterForDrag("LeftButtton");
			MyStoreFrameTab1.tooltip = "Administration\nConsole";
			MyStoreFrameTab2.tooltip = "Known Stores\nList";
			MyStoreFrameTab3.tooltip = "Current Store";
			MyStoreFrameTab1:SetNormalTexture("Interface\\Icons\\INV_Misc_Wrench_02");
			MyStoreFrameTab2:SetNormalTexture("Interface\\Icons\\INV_Misc_Note_05");
			MyStoreFrameTab3:SetNormalTexture("Interface\\AddOns\\MyStore\\Images\\MyS_Register");
		end;

		resetPos = function()
			MyStoreFrame:ClearAllPoints();
			MyStoreFrame:SetPoint("TOPLEFT","UIParent","TOPLEFT",0,-104);
		end;

		onShow = function()
			if ( MyS.bgFrame.selectedTab == 3 ) then
				MyS.bgFrame.tabClick(1);
			else
				MyS.bgFrame.tabClick(MyS.bgFrame.selectedTab);
			end
			MyStoreFrameTab3:Hide();
		end;

		onHide = function()
			if ( MyS.cust.currentStore ) then
				SendChatMessage("<MyStore>!CUST!CLOSESTORE!", "WHISPER", DEFAULT_CHAT_FRAME.language, MyS.cust.currentStore);
			end
			MyS.cust.currentStore = nil;
		end;

		tabClick = function(id)
			if ( not id ) then
				id = this:GetID();
			end
			MyS.bgFrame.selectedTab = id;
			if ( id == 1 ) then
				-- Admin id clicked
				MyStoreFrameTab1:SetChecked(1);
				MyStoreFrameTab2:SetChecked(nil);
				MyStoreFrameTab3:SetChecked(nil);
				A_MerchantFrame:Show()
				C_MerchantFrame:Hide()
				MyS_StoreList:Hide()
			elseif ( id == 2 ) then
				-- Store List id clicked
				MyStoreFrameTab1:SetChecked(nil);
				MyStoreFrameTab2:SetChecked(1);
				MyStoreFrameTab3:SetChecked(nil);
				A_MerchantFrame:Hide()
				C_MerchantFrame:Hide()
				MyS_StoreList:Show()
			elseif ( id == 3 ) then
				-- current store id clicked
				MyStoreFrameTab1:SetChecked(nil);
				MyStoreFrameTab2:SetChecked(nil);
				MyStoreFrameTab3:SetChecked(1);
				A_MerchantFrame:Hide()
				C_MerchantFrame:Show()
				MyS_StoreList:Hide()
			end
			if ( id == 1 or id == 3 ) then
				MyS_TopLeft:SetTexture("Interface\\MerchantFrame\\UI-Merchant-TopLeft");
				MyS_TopRight:SetTexture("Interface\\MerchantFrame\\UI-Merchant-TopRight");
				MyS_BotLeft:SetTexture("Interface\\MerchantFrame\\UI-Merchant-BotLeft");
				MyS_BotRight:SetTexture("Interface\\MerchantFrame\\UI-Merchant-BotRight");
				MyS_TopLeft:SetPoint("TOPLEFT", "MyStoreFrame", "TOPLEFT", 0, 0);
			else
				MyS_TopLeft:SetTexture("Interface\\ItemTextFrame\\UI-ItemText-TopLeft");
				MyS_TopRight:SetTexture("Interface\\Spellbook\\UI-SpellbookPanel-TopRight");
				MyS_BotLeft:SetTexture("Interface\\ItemTextFrame\\UI-ItemText-BotLeft");
				MyS_BotRight:SetTexture("Interface\\Spellbook\\UI-SpellbookPanel-BotRight");
				MyS_TopLeft:SetPoint("TOPLEFT", "MyStoreFrame", "TOPLEFT", -2, 1);
			end
			PlaySound("igSpellBookOpen");
		end;
	};

	storeList = {
		page = 1;

		add = function(data,store,channel)
			if ( MyS.storeList.blackList.isListed(store) ) then
				return;
			end

			-- <MyStore> Store open! [Item] - 5g20s0c
			-- I split the regex up so that store owner's can customize their ads:
			-- for example, someone may want to have:
			-- <MyStore> Store open! Featured Item: [Item] for only 5g20s0c!

			local _,_,link,count = strfind(data,"(|c%x+|Hitem:%d+:%d+:%d+:%d+|h%[.+]|h|r)x(%d+)");
			local _,_,g,s,c = strfind(data,"(%d+)g(%d+)s(%d+)c");
			local name = MyS_AuxFunc.getNameFromLink(link);

			if ( link and count and name and g and s and c ) then
				if ( tonumber(s) < 10 ) then
					s = "0"..s;
				end
				if ( tonumber(c) < 10 ) then
					c = "0"..c;
				end

				local index = MyS_Session.advertisedStoresIdx[store];
				local newStore = {
					["store"] = store,
					["link"] = link,
					["cost"] = tonumber(g..s..c),
					["name"] = name,
					["count"] = tonumber(count),
					["lastUpdate"] = GetTime(),
					["lastUpdatePretty"] = date(),
					["lastUpdateChannel"] = channel,
					["threeChecks"] = 1,
				};

				if ( not index ) then
					tinsert(MyS_Session.advertisedStores, newStore);
					MyS_Session.advertisedStoresIdx[store] = getn(MyS_Session.advertisedStores);
				elseif ( index and MyS_Session.advertisedStores[index] and MyS_Session.advertisedStores[index].lastUpdate and MyS_Session.advertisedStores[index].lastUpdateChannel ) then
					if ( ((GetTime() + 5) < (MyS_Session.advertisedStores[index].lastUpdate + ANNOUNCE_INTERVAL)) and MyS_Session.advertisedStores[index].lastUpdateChannel == channel ) then
						if ( MyS_Session.advertisedStores[index].threeChecks < 3 ) then
							MyS_Session.advertisedStores[index].threeChecks = MyS_Session.advertisedStores[index].threeChecks + 1;
							MyS_AuxFunc.chatMessage(store.." being watched for abuse.  "..(4 - MyS_Session.advertisedStores[index].threeChecks).." strikes left.",1);
						else
							local offset = (MyS_Session.advertisedStores[index].lastUpdate + ANNOUNCE_INTERVAL) - GetTime();
							MyS_AuxFunc.chatMessage(store.." added to blacklist ("..offset.." sec too soon)",1);
							MyS.storeList.blackList.add(store);
						end
					else
						newStore.threeChecks = MyS_Session.advertisedStores[index].threeChecks;
						MyS_Session.advertisedStores[index] = newStore;
					end
				end

				if ( not MyStoreFrameTab2:IsVisible() ) then
					MyStoreFrameTab2:Show();
				end
				if ( MyStoreFrame:IsVisible() ) then
					MyS.storeList.refresh();
				end
			end
		end;

		blackList = {
			add = function(store)
				if ( not MyS.storeList.blackList.isListed(store) ) then
					tinsert(MyS_Config["Blacklist"],strupper(store).."|"..GetCVar("realmName"));
				end
			end;

			delete = function(store)
				if ( MyS.storeList.blackList.isListed(store) ) then
					tremove(MyS_Config["Blacklist"],MyS.storeList.blackList.isListed(store));
				end
			end;

			show = function()
				local cstr = "Blacklisted stores:";
				local found;
				for key, val in MyS_Config["Blacklist"] do
					local _,_,name = strfind(val,"(.+)|"..GetCVar("realmName"));
					cstr = cstr.."\n"..strsub(name,1,1)..strlower(strsub(name,2));
					found = 1;
				end
				if ( found ) then
					MyS_AuxFunc.chatMessage(cstr);
				else
					MyS_AuxFunc.chatMessage(cstr.."\n[Empty]");
				end
			end;

			isListed = function(store)
				if ( not MyS_Config["Blacklist"] ) then
					MyS_Config["Blacklist"] = {};
				else
					for key,val in MyS_Config["Blacklist"] do
						if ( (strupper(store).."|"..GetCVar("realmName")) == val ) then
							return key;
						end
					end
				end
			end;			
		};

		onShow = function()
			MyS.storeList.refresh();
		end;

		onEnter = function(index)
			if ( not index ) then
				index = this.index;
			end
			GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
			GameTooltip:SetHyperlink(this.link);
		end;

		onClick = function(store)
			if ( not store ) then
				store = this.store;
			end
			getglobal(this:GetParent():GetName().."ExpireTime"):SetText("Connecting...");
			MyS.cust.openStore(this.store);
		end;

		refresh = function()
			local numItems = getn(MyS_Session.advertisedStores);
			local index = ((MyS.storeList.page - 1) * INBOXITEMS_TO_DISPLAY) + 1;
			local button, buttonIcon, buttonCount, buttonLink, subjectText, senderText, expireTime, item;

			for i = 1, INBOXITEMS_TO_DISPLAY do
				item = MyS_Session.advertisedStores[index];
				if ( index <= numItems and item ) then
					button = getglobal("MyS_StoreListItem"..i.."Button");
					button:Show();
					button.index = index;
					_,_,buttonLink = strfind(item.link,"|H(item:%d+:%d+:%d+:%d+)|");
					button.link = buttonLink;
					button.store = item.store;
					buttonIcon = getglobal("MyS_StoreListItem"..i.."ButtonIcon");
					buttonIcon:SetTexture("Interface\\Icons\\Spell_Nature_Lightning");
					subjectText = getglobal("MyS_StoreListItem"..i.."Subject");
					subjectText:SetText(item.name.." - "..MyS_AuxFunc.getMoneyString(item.cost));
					senderText = getglobal("MyS_StoreListItem"..i.."Sender");
					senderText:SetText(item.store);
					expireTime = getglobal("MyS_StoreListItem"..i.."ExpireTime");
					expireTime:SetText(item.lastUpdatePretty);
					expireTime:Show();

					buttonCount = getglobal("MyS_StoreListItem"..i.."ButtonCount");
					if ( item.count > 1 ) then
						buttonCount:SetText(item.count);
						buttonCount:Show();
					else
						buttonCount:Hide();
					end
				else
					getglobal("MyS_StoreListItem"..i.."Button"):Hide();
					getglobal("MyS_StoreListItem"..i.."ExpireTime"):Hide();
					getglobal("MyS_StoreListItem"..i.."Sender"):SetText("");
					getglobal("MyS_StoreListItem"..i.."Subject"):SetText("");
				end
				index = index + 1;
			end

			-- Handle page arrows
			if ( MyS.storeList.page == 1 ) then
				MyS_StoreListPrevPageButton:Disable();
			else
				MyS_StoreListPrevPageButton:Enable();
			end
			if ( (MyS.storeList.page * INBOXITEMS_TO_DISPLAY) < numItems ) then
				MyS_StoreListNextPageButton:Enable();
			else
				MyS_StoreListNextPageButton:Disable();
			end
		end;
	};

	--[[	BEGIN Customer functions ******************** ]]
	cust = {
		currentStore = nil;
		page = 1;

		saveItem = function(data,store)
			local _,_,id,texture,color,q1,q2,q3,q4,name,count,quantity,cost,inCart = strfind(data,"!ITEMID!(%d+)!TEX!(.+)!COLR!(%x+)!Q1!(%d+)!Q2!(%d+)!Q3!(%d+)!Q4!(%d+)!N!(.+)!C!(%d+)!QUAN!(%d+)!COST!(%d+)!CART!(%d+)");
			if ( id and texture and q1 and q2 and q3 and q4 and name and count and quantity and cost ) then
				MyS_Session.knownStores[store][tonumber(id)] = {
					["texture"] = texture,
					["count"] = tonumber(count),
					["quantity"] = tonumber(quantity),
					["cost"] = tonumber(cost),
					["link"] = MyS.makeLink(color,q1,q2,q3,q4,name)
				};
				if ( inCart == "1" ) then
					MyS_Session.knownStores[store][tonumber(id)]["inCart"] = 1;
				end
			end
		end;

		getItemInfo = function(store,index)
			-- return name, texture, price, quantity, numAvailable, isUsable;
			-- numAvailable is the number in stock, -1 = just the one shown
			if ( store and index ) then
				local item = MyS_Session.knownStores[store][index];
				if ( item ) then
					local q = item.quantity;
					if ( q == 1 ) then
						q = -1;
					end
					local cartStatus;
					if ( item.inCart ) then
						cartStatus = 1;
					else
						cartStatus = nil;
					end
					return MyS_AuxFunc.getNameFromLink(item.link), item.texture, item.cost, item.count, q, cartStatus;
				end
			end
		end;

		initStore = function(data,store)
			local _,_,pass = strfind(data,"!PASS!("..UnitName("player").."%d+)");
			if ( not pass ) then return; end
			if ( pass == MyS_Session.clientPass ) then
				MyS.cust.currentStore = store;
				MyS.cust.page = 1;
				MyS.cust.clearStore(store);
				MyStoreFrameTab3:Show();

				local index = MyS_Session.advertisedStoresIdx[store];

				if ( not index ) then
					return;
				else
					MyS_Session.advertisedStores[index].lastUpdatePretty = date();
				end
			end
		end;

		setStatus = function(data,store)
			local _,_,status,zone,x,y = strfind(data,"!STATUS!(.+)!ZONE!(.+)!X!(%d+)!Y!(%d+)");
			local zoneText = "\n"..zone.." (X,Y): "..HIGHLIGHT_FONT_COLOR_CODE..x..","..y.."|r";
			if ( MyS_Session.knownStores[store] and status and MyS.cust.currentStore == store ) then
				if ( status == "OPEN" ) then
					C_MerchantBottomButton1:Enable();
					C_MerchantBottomButton2:Enable();
					C_MerchantNameText:SetText("MyStore "..MyS.version.."\n\nViewing Store - "..store..GREEN_FONT_COLOR_CODE.." [OPEN]|r"..zoneText);
				elseif ( status == "CLOSED" ) then
					C_MerchantBottomButton1:Disable();
					C_MerchantBottomButton2:Disable();
					C_MerchantNameText:SetText("MyStore "..MyS.version.."\n\nViewing Store - "..store..GRAY_FONT_COLOR_CODE.." [CLOSED]|r"..zoneText);
				elseif ( status == "MAIL" ) then
					C_MerchantBottomButton1:Disable();
					C_MerchantBottomButton2:Enable();
					C_MerchantNameText:SetText("MyStore "..MyS.version.."\n\nViewing Store - "..store.."|cffbfffbf [MAIL-ONLY]|r"..zoneText);
				end
				MyS_Session.knownStores[store].status = status;
			end
		end;

		openStore = function(store)
			if ( MyS.cust.currentStore and MyS.cust.currentStore == store ) then
				MyS_AuxFunc.chatMessage("Refreshing "..store.."'s Store...");
			else
				MyS_AuxFunc.chatMessage("Opening "..store.."'s Store...");
			end
			MyS.cust.sendPass(store);
			MyS_Comm.msgOut("!OPENSTORE!",store,1);
		end;

		sendDeny = function(store)
			MyS_Comm.msgOut("!BADPASS!",store,1);
			MyS_AuxFunc.chatMessage("Handshake error with "..store.."...",1);
		end;

		compareTotals = function(data,store)
			local _,_,total = strfind(data, "!TOTALITEMS!(%d+)");
			if ( total and MyS_Session.knownStores[store] ) then
				total = tonumber(total);
				if ( total == MyS.cust.getTotalItems(store) and MyS.cust.currentStore == store ) then
					MyS.cust.refreshStore(store);
					MyS.bgFrame.tabClick(3);
					MyStoreFrame:Show();
				end
			end
		end;

		clearStore = function(store)
			MyS_Session.knownStores[store] = {};
			if ( C_MerchantFrame:IsVisible() and MyS.cust.currentStore == store ) then
				C_MerchantNameText:SetText("MyStore "..MyS.version.."\n\nUpdating Store - "..store);
			end
		end;

		sendPass = function(store)
			MyS_Comm.msgOut("!SESSIONPASS!"..MyS_Session.clientPass,store,1);
		end;

		sendRefresh = function(store)
			MyS_Comm.msgOut("!REFRESH!",store,1);
		end;

		refreshCartTotal = function(store)
			if ( not MyS_Session.knownStores[store] ) then return; end
			local cartPrice = 0;
			for index, val in MyS_Session.knownStores[store] do
				if ( tonumber(index) and val.inCart ) then
					cartPrice = cartPrice + val.cost;
				end
			end
			MoneyFrame_Update("C_MerchantCartMoneyFrame", cartPrice);
		end;

		getTotalItems = function(store)
			if ( not MyS_Session.knownStores[store] ) then return; end
			local highest = 0;
			for index, val in MyS_Session.knownStores[store] do
				if ( tonumber(index) and highest < index ) then
					highest = index;
				end
			end
			return highest;
		end;

		refreshStore = function(store)
			local thisStore = MyS_Session.knownStores[store];

			C_MerchantNameText:SetText("MyStore "..MyS.version.."\n\nViewing Store - "..store);

			if ( UnitName("target") == store ) then
				SetPortraitTexture(MyS_Portrait, "target");
			else
				MyS_Portrait:SetTexture("Interface\\AddOns\\MyStore\\Images\\MyStorePortrait");
			end

			C_MerchantPageText:SetText(format(TEXT(PAGE_NUMBER), MyS.cust.page));
			local highestMerchantItem = MyS.cust.getTotalItems(store);
			local name, texture, price, count, numInStock, isUsable;
			for i=1, MERCHANT_ITEMS_PER_PAGE, 1 do
				local index = (((MyS.cust.page - 1) * MERCHANT_ITEMS_PER_PAGE) + i);
				local itemButton = getglobal("C_MerchantItem"..i.."ItemButton");
				local merchantButton = getglobal("C_MerchantItem"..i);
				itemButton:SetID(index);
				if ( index <= highestMerchantItem and thisStore[index] ) then
					name, texture, price, count, numInStock, inCart = MyS.cust.getItemInfo(store,index);
					getglobal("C_MerchantItem"..i.."Name"):SetText(name);
					SetItemButtonCount(itemButton, count);
					SetItemButtonStock(itemButton, numInStock);
					SetItemButtonTexture(itemButton, texture);
					getglobal("C_MerchantItem"..i.."MoneyFrame"):Show();
					MoneyFrame_Update("C_MerchantItem"..i.."MoneyFrame", price);
					itemButton:Show();
					if ( numInStock == 0 ) then
						-- If not available and not usable
						if ( not isUsable ) then
							SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0, 0);
							SetItemButtonSlotVertexColor(merchantButton, 0.5, 0, 0);
							SetItemButtonTextureVertexColor(itemButton, 0.5, 0, 0);
							SetItemButtonNormalTextureVertexColor(itemButton, 0.5, 0, 0);
						else
							SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
							SetItemButtonSlotVertexColor(merchantButton, 0.5, 0.5, 0.5);
							SetItemButtonTextureVertexColor(itemButton, 0.5, 0.5, 0.5);
							SetItemButtonNormalTextureVertexColor(itemButton,0.5, 0.5, 0.5);
						end
					elseif ( inCart ) then
						SetItemButtonNameFrameVertexColor(merchantButton, 0, 1.0, 0);
						SetItemButtonSlotVertexColor(merchantButton, 0, 1.0, 0);
						SetItemButtonTextureVertexColor(itemButton, 0, 0.9, 0);
						SetItemButtonNormalTextureVertexColor(itemButton, 0, 0.9, 0);
					else
						SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
						SetItemButtonSlotVertexColor(merchantButton, 1.0, 1.0, 1.0);
						SetItemButtonTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
						SetItemButtonNormalTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
					end
				else
					SetItemButtonCount(itemButton, 0);
					SetItemButtonTexture(itemButton, "");
					SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
					SetItemButtonSlotVertexColor(merchantButton,0.4, 0.4, 0.4);
					SetItemButtonTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
					SetItemButtonNormalTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
					getglobal("C_MerchantItem"..i.."Name"):SetText("");
					getglobal("C_MerchantItem"..i.."MoneyFrame"):Hide();
				end
			end

			-- Handle featured item
			local FeaturedName, FeaturedTexture, FeaturedPrice, FeaturedCount, FeaturedNumAvailable, FeaturedInCart = MyS.cust.getItemInfo(store,0);
			if ( FeaturedName ) then
				if ( FeaturedInCart ) then
					SetItemButtonNameFrameVertexColor(C_MerchantFeaturedItem, 0, 1.0, 0);
					SetItemButtonSlotVertexColor(C_MerchantFeaturedItem, 0, 1.0, 0);
					SetItemButtonTextureVertexColor(C_MerchantFeaturedItemItemButton, 0, 0.9, 0);
					SetItemButtonNormalTextureVertexColor(C_MerchantFeaturedItemItemButton, 0, 0.9, 0);
				else
					SetItemButtonNameFrameVertexColor(C_MerchantFeaturedItem, 0.5, 0.5, 0.5);
					SetItemButtonSlotVertexColor(C_MerchantFeaturedItem, 1.0, 1.0, 1.0);
					SetItemButtonTextureVertexColor(C_MerchantFeaturedItemItemButton, 1.0, 1.0, 1.0);
					SetItemButtonNormalTextureVertexColor(C_MerchantFeaturedItemItemButton, 1.0, 1.0, 1.0);
				end
				SetItemButtonCount(C_MerchantFeaturedItemItemButton, FeaturedCount);
				SetItemButtonStock(C_MerchantFeaturedItemItemButton, FeaturedNumAvailable);
				SetItemButtonTexture(C_MerchantFeaturedItemItemButton, FeaturedTexture);
				C_MerchantFeaturedItemName:SetText(FeaturedName);
				C_MerchantFeaturedItemMoneyFrame:Show();
				MoneyFrame_Update("C_MerchantFeaturedItemMoneyFrame", FeaturedPrice);
				C_MerchantFeaturedItem:Show();
			else
				C_MerchantFeaturedItemName:SetText("No Featured Item");
				C_MerchantFeaturedItemMoneyFrame:Hide();
				SetItemButtonTexture(C_MerchantFeaturedItemItemButton, "");
				SetItemButtonCount(C_MerchantFeaturedItemItemButton, 0);
				SetItemButtonNameFrameVertexColor(C_MerchantFeaturedItem, 0.5, 0.5, 0.5);
				SetItemButtonTextureVertexColor(C_MerchantFeaturedItemItemButton, 1.0, 1.0, 1.0);
				SetItemButtonNormalTextureVertexColor(C_MerchantFeaturedItemItemButton, 1.0, 1.0, 1.0);
				SetItemButtonSlotVertexColor(C_MerchantFeaturedItem, 0.4, 0.4, 0.4);
				-- Hide the tooltip upon sale
				if ( GameTooltip:IsOwned(C_MerchantFeaturedItemItemButton) ) then
					GameTooltip:Hide();
				end
			end

			-- Handle paging buttons
			if ( highestMerchantItem >= MERCHANT_ITEMS_PER_PAGE ) then
				if ( MyS.cust.page == 1 ) then
					C_MerchantPrevPageButton:Disable();
				else
					C_MerchantPrevPageButton:Enable();
				end
				if ( MyS.cust.page == ceil((highestMerchantItem + 1) / MERCHANT_ITEMS_PER_PAGE) or highestMerchantItem == 0) then
					C_MerchantNextPageButton:Disable();
				else
					C_MerchantNextPageButton:Enable();
				end
				C_MerchantPageText:Show();
				C_MerchantPrevPageButton:Show();
				C_MerchantNextPageButton:Show();
			else
				C_MerchantPageText:Hide();
				C_MerchantPrevPageButton:Hide();
				C_MerchantNextPageButton:Hide();
			end

			MyS.cust.refreshCartTotal(store);
		end;

		prevButton_OnClick = function()
			PlaySound("igMainMenuOptionCheckBoxOn");
			MyS.cust.page = MyS.cust.page - 1;
			MyS.cust.refreshStore(MyS.cust.currentStore);
		end;

		nextButton_OnClick = function()
			PlaySound("igMainMenuOptionCheckBoxOn");
			MyS.cust.page = MyS.cust.page + 1;
			MyS.cust.refreshStore(MyS.cust.currentStore);
		end;

		addToCart = function(store,id)
			if ( MyS_Session.knownStores[store] and MyS_Session.knownStores[store].status and MyS_Session.knownStores[store].status ~= "CLOSED" and MyS_Session.knownStores[store][id] and not MyS_Session.knownStores[store][id].inCart ) then
				local cartLink = "!ADD2CART!ITEMID!"..id;
				MyS_Comm.msgOut(cartLink,store,1);
			end
		end;

		verifyCart = function(data,store)
			local _,_,id,status,q = strfind(data,"!VRFYCART!ITEMID!(%d+)!(.+)!Q!(%d+)");
			id = tonumber(id);
			q = tonumber(q);

			if ( MyS_Session.knownStores[store][id] ) then
				if ( status == "SUCCESS" ) then
					MyS_Session.knownStores[store][id].inCart = 1;
					MyS_Session.knownStores[store][id].quantity = q;
				elseif ( status == "REMOVED" ) then
					MyS_Session.knownStores[store][id].inCart = nil;
					MyS_Session.knownStores[store][id].quantity = q;
				elseif ( status == "FAIL" ) then
					MyS_Session.knownStores[store][id].quantity = 0;
					MyS_Session.knownStores[store][id].inCart = nil;
				end
			else
				MyS_Session.knownStores[store][id] = nil;
			end
			if ( MyS.cust.currentStore == store ) then
				MyS.cust.refreshStore(store);
			end
		end;

		removeFromCart = function(store,id)
			if ( MyS_Session.knownStores[store] and MyS_Session.knownStores[store][id] and MyS_Session.knownStores[store][id].inCart ) then
				local cartLink = "!REMOVECART!ITEMID!"..id;
				MyS_Comm.msgOut(cartLink,store,1);
			end
		end;

		showTradeCost = function(data,store)
			local _,_,money = strfind(data,"!TRADETOTAL!(%d+)");
			money = tonumber(money);
			MyS_AuxFunc.chatMessage("The total for this trade is :"..MyS_AuxFunc.getMoneyString(money)..".");
		end;

		BottomBtn1 = {
			onClick = function()
				if ( UnitName("target") == MyS.cust.currentStore ) then
					InitiateTrade("target");
				end
			end;
		};

		item = {
			onEnter = function()
				if ( not MyS_Session.knownStores[MyS.cust.currentStore][this:GetID()] ) then
					return;
				end
				local myLink = MyS_Session.knownStores[MyS.cust.currentStore][this:GetID()].link;
				if ( myLink and strlen(myLink) > 0 ) then
					GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
					_,_,myLink = strfind(myLink,"|H(item:%d+:%d+:%d+:%d+)|");
					GameTooltip:SetHyperlink(myLink);
				end
			end;

			onClick = function(button,featured)
				if ( button == "LeftButton" ) then
					MyS.cust.addToCart(MyS.cust.currentStore,this:GetID());
				else
					MyS.cust.removeFromCart(MyS.cust.currentStore,this:GetID());
				end
			end;
		};
	};

	--[[	BEGIN Store functions *********************** ]]
	stor = {
		page = 1;

		onEvent = function(event)
			-- Nothing
		end;

		onShow = function()
			SetPortraitTexture(MyS_Portrait, "player");
			MyS.stor.readLive();
			MyS.stor.page = 1;
			MyS.stor.refreshFrame();
			MyS.stor.refreshButtons();

			UIDropDownMenu_Initialize(A_MerchantBottomButton2DropDown, MyS.stor.BottomBtn2.dropdownInit, "MENU");
		end;

		sendRefresh = function(client)
			MyS_Comm.msgOut("!REFRESH!PASS!"..MyS.stor.getClientPass(client),client);
		end;

		getTotalClients = function()
			local count = 0;
			for index, val in MyS_Session.currentClients do
				if ( val.active ) then
					count = count + 1;
				end
			end
			return count;
		end;

		saveClientPass = function(arg1,client)
			local _,_,password = strfind(arg1,"!SESSIONPASS!("..client.."%d+)")
			if ( password ) then
				if ( not MyS_Session.currentClients[client] ) then
					MyS_Session.currentClients[client] = {
						["active"] = 1,
						["password"] = password,
						["cart"] = {}
					};
				else
					MyS_Session.currentClients[client].password = password;
					MyS_Session.currentClients[client].active = 1;
				end
			end
		end;

		removeClient = function(client)
			if ( MyS_Session.currentClients[client] and MyS_Session.currentClients[client].active ) then
				MyS_Session.currentClients[client].active = nil;
			end
			if ( MyS_Comm.COMMAND_QUEUE[client] ) then
				MyS_Comm.COMMAND_QUEUE[client] = {};
			end
		end;

		getClientPass = function(client)
			if ( MyS_Session.currentClients[client] and MyS_Session.currentClients[client].password ) then
				return MyS_Session.currentClients[client].password;
			else
				return -1;
			end
		end;

		sendOpen = function(client)
			if ( MyS_Session.currentClients[client] and MyS_Session.currentClients[client].password ) then
				MyS_Comm.msgOut("!OPENSTORE!PASS!"..MyS_Session.currentClients[client].password,client);
				MyS.stor.sendItems(client);
			else
				MyS_AuxFunc.chatMessage("No client password found.",1);
			end
		end;

		sendItems = function(client)
			for index, val in MyS_Session.user.saleItems do
				if ( not MyS.stor.getItemInfo(index,1) ) then
					if ( MyS_Session.lockedItems[index] ) then
						MyS_Session.lockedItems[index] = nil;
					end
					MyS_Session.user.saleItems[index] = nil;
				else
					local cart = 0;
					if ( MyS_Session.lockedItems[index] and MyS_Session.lockedItems[index] ~= client ) then
						q = 0;
					elseif ( MyS_Session.lockedItems[index] and MyS_Session.lockedItems[index] == client ) then
						q = val.quantity;
						cart = 1;
					else
						q = val.quantity;
					end
					local storeLink = "!ITEMID!"..index.."!TEX!"..val.texture..MyS.splitLink(val.link).."!C!"..val.count.."!QUAN!"..q.."!COST!"..val.cost.."!CART!"..cart;
					MyS_Comm.msgOut(storeLink,client);
				end
			end
			if ( MyS.stor.getItemInfo(0,1) ) then
				local item = MyS_Session.user.saleItems[0];
				local storeLink = "!ITEMID!0!TEX!"..item.texture..MyS.splitLink(item.link).."!C!"..item.count.."!QUAN!"..item.quantity.."!COST!"..item.cost;
				MyS_Comm.msgOut(storeLink,client);
			else
				MyS_Session.user.saleItems[0] = nil;
			end

			MyS.stor.sendTotal(client);
			MyS.stor.sendStatus(client);
		end;

		sendTotal = function(client)
			MyS_Comm.msgOut("!TOTALITEMS!"..MyS.stor.getTotalItems(1),client);
		end;

		sendStatus = function(client)
			MyS_AuxFunc.chatMessage("Sending status to "..client,1);
			local x,y,zone,subzone = MyS_AuxFunc.getPos();
			local zoneText = "!ZONE!"..zone.."!X!"..x.."!Y!"..y;
			if ( MyS_Session.user.open and MyS_Session.user.open == 1 ) then
				MyS_Comm.msgOut("!STATUS!OPEN"..zoneText,client);
			elseif ( MyS_Session.user.open and MyS_Session.user.open == 2 ) then
				MyS_Comm.msgOut("!STATUS!MAIL"..zoneText,client);
			else
				MyS_Comm.msgOut("!STATUS!CLOSED"..zoneText,client);
			end
		end;

		readLive = function ()
			MyS_Session.tempStore = nil;
			MyS_Session.tempStore = MyS_AuxFunc.copyTable(MyS_Session.user.saleItems);
		end;

		refreshClient = function(client)
			if ( MyS_Session.currentClients[client] and MyS_Session.currentClients[client].active ) then
				MyS.stor.sendRefresh(client);
				MyS.stor.sendItems(client);
			end
		end;

		refreshClients = function()
			for client, data in MyS_Session.currentClients do
				if ( data.password and data.active ) then
					MyS.stor.sendRefresh(client);
					MyS.stor.sendItems(client);
				end
			end
		end;

		clearAllItems = function()
			MyS_Session.tempStore = {};
			MyS.stor.refreshFrame();
		end;

		goLive = function ()
			MyS_Session.user.saleItems = nil;
			MyS_Session.user.saleItems = MyS_AuxFunc.copyTable(MyS_Session.tempStore);
		end;

		announce = function(index,popTarget)
			if ( MyS_Session.user.open and MyS_Session.user.open == 1 ) then
				if ( not index and MyS.stor.getTotalItems(1) > 0 ) then
					local rndTable = {};
					for key, val in MyS_Session.user.saleItems do
						tinsert(rndTable,key);
					end
					index = rndTable[random(getn(rndTable))];
				end
				local item = MyS_Session.user.saleItems[index];

				if ( item ) then
					MyS_Comm.announce("<MyStore> Store open! "..item.link.."x"..item.count.." - "..MyS_AuxFunc.getMoneyString(item.cost),popTarget);
				end
			end
		end;

		getTotalItems = function(live)
			local highest = 0;
			if ( live ) then
				for index, val in MyS_Session.user.saleItems do
					if ( index > highest ) then
						highest = index;
					end
				end
			else
				for index, val in MyS_Session.tempStore do
					if ( index > highest ) then
						highest = index;
					end
				end
			end
			return highest;
		end;

		checkData = function(live)
			local data;
			if ( live ) then
				data = MyS_Session.user.saleItems;
			else
				data = MyS_Session.tempStore;
			end

			for index, item in data do
				local texture, count = GetContainerItemInfo(item.bag, item.slot);
				local link = GetContainerItemLink(item.bag,item.slot);

				if ( not count or not link or ( item.count ~= count or item.link ~= link ) ) then
					if ( live and MyS_Session.lockedItems[index] ) then
						MyS_Session.lockedItems[index] = nil;
					end
					data[index] = nil;
				end
			end
			MyS.stor.refreshFrame();
		end;

		getItemInfo = function(index,live)
			-- return name, texture, price, quantity, numAvailable, isUsable;
			-- numAvailable is the number in stock, -1 = just the one shown
			local item;
			if ( live ) then
				item = MyS_Session.user.saleItems[index];
				cartStatus = MyS_Session.lockedItems[index];
			else
				item = MyS_Session.tempStore[index];

				local liveItem = MyS_Session.user.saleItems[index];
				if ( item and liveItem and liveItem.link == item.link and liveItem.count == item.count ) then
					-- If the temp item is the same as the live item, then check cart status
					cartStatus = MyS_Session.lockedItems[index];
				end
			end
			if ( item and item.bag and item.slot ) then
				local texture, count = GetContainerItemInfo(item.bag, item.slot);
				local link = GetContainerItemLink(item.bag,item.slot);

				if ( item.count == count and item.link == link ) then
					return MyS_AuxFunc.getNameFromLink(item.link), item.texture, item.cost, item.count, -1, cartStatus;
				end
			end
		end;

		getFirstEmptySlot = function()
			for index = 1, getn(MyS_Session.tempStore) + 1 do
				if ( not MyS_Session.tempStore[index] ) then
					return index;
				end
			end
			return 0;
		end;

		getItemDefaultPrice = function(itemName)
			if ( MyS_Config.useSellValue and SellValues and SellValues[itemName] and SellValues[itemName] > 0 ) then
				return SellValues[itemName] * MyS_Config.useSellValueMultiplier;
			elseif ( MyS_Config.useSellValue and ItemLinks and ItemLinks[itemName] and ItemLinks[itemName].p and ItemLinks[itemName].p > 0 ) then
				return ItemLinks[itemName].p * MyS_Config.useSellValueMultiplier;
			else
				return MyS_Config.defaultPrice;
			end
		end;

		openMoneyEditor = function(frameName)
			if ( frameName == "A_MerchantFeaturedItem" ) then
				MyS.stor.showMoneyEditor(0,"A_MerchantFeaturedItem");
			elseif ( frameName ) then
				for num=1, MERCHANT_ITEMS_PER_PAGE do
					if ( frameName == "A_MerchantItem"..num ) then
						MyS.stor.showMoneyEditor((((MyS.stor.page - 1) * MERCHANT_ITEMS_PER_PAGE) + num),frameName);
						break;
					end
				end
			end
		end;

		showMoneyEditor = function(index,frameName)
			if ( MyS_Session.tempStore[index] ) then
				MyS_MoneyEdit:SetID(index);
				local item = MyS_Session.tempStore[index];
				local itemButton = getglobal("MyS_MoneyEditItemButton");

				SetItemButtonCount(itemButton, item.count);
				SetItemButtonTexture(itemButton, item.texture);
				MyS_MoneyEditName:SetText(MyS_AuxFunc.getNameFromLink(item.link));
				itemButton:SetID(index);
				MoneyInputFrame_SetCopper(MyS_MoneyEditTextBox,item.cost);
				MyS_MoneyEdit:Show();
			end
		end;

		moneyEditOkay = function()
			local index = MyS_MoneyEdit:GetID();
			local money = MoneyInputFrame_GetCopper(MyS_MoneyEditTextBox);

			if ( MyS_Session.tempStore[index] ) then
				MyS_Session.tempStore[index].cost = money;
			else
				MyS.stor.removeItem(index);
			end
			MyS.stor.refreshFrame();
			MyS_MoneyEdit:Hide();
		end;

		isListed = function(bag,slot)
			for index, val in MyS_Session.tempStore do
				if ( val.bag == bag and val.slot == slot ) then
					return 1;
				end
			end
		end;

		addItem = function(bag,slot,index,price)
			local texture, itemCount = GetContainerItemInfo(bag,slot);
			local link = GetContainerItemLink(bag,slot);

			if ( MyS.stor.isListed(bag,slot) ) then return; end

			if ( not index ) then
				index = MyS.stor.getFirstEmptySlot();
			end

			if ( texture and itemCount and link ) then
				local itemInfo = {
					["bag"] = bag,
					["slot"] = slot,
					["texture"] = texture,
					["count"] = itemCount,
					["quantity"] = 1,
					["cost"] = MyS.stor.getItemDefaultPrice(MyS_AuxFunc.getNameFromLink(link)),
					["link"] = link
				};
				if ( price ) then
					itemInfo.cost = price;
				end
				MyS_Session.tempStore[index] = itemInfo;
				MyS.stor.refreshFrame();
			end
		end;

		removeItem = function(index)
			if ( index and MyS_Session.tempStore[index] ) then
				MyS_Session.tempStore[index] = nil;
				MyS.stor.refreshFrame();
			end
		end;

		refreshFrame = function()
			A_MerchantNameText:SetText("MyStore "..MyS.version.."\n\nAdministration Panel - "..UnitName("player").."\nTotal Sales Today: "..MyS_Session.stats.sales);
			SetPortraitTexture(MyS_Portrait, "player");
			A_MerchantPageText:SetText(format(TEXT(PAGE_NUMBER), MyS.stor.page));
			local highestMerchantItem = MyS.stor.getTotalItems();
			local name, texture, price, count, numInStock, inCart;
			for i=1, MERCHANT_ITEMS_PER_PAGE, 1 do
				local index = (((MyS.stor.page - 1) * MERCHANT_ITEMS_PER_PAGE) + i);
				local itemButton = getglobal("A_MerchantItem"..i.."ItemButton");
				local merchantButton = getglobal("A_MerchantItem"..i);
				itemButton:SetID(index);

				name, texture, price, count, numInStock, inCart = MyS.stor.getItemInfo(index);

				if ( inCart ) then
					itemButton.locked = inCart;
				else
					itemButton.locked = nil;
				end

				if ( index <= highestMerchantItem and name ) then
					getglobal("A_MerchantItem"..i.."Name"):SetText(name);
					SetItemButtonCount(itemButton, count);
					SetItemButtonStock(itemButton, numInStock);
					SetItemButtonTexture(itemButton, texture);
					getglobal("A_MerchantItem"..i.."MoneyFrame"):Show();
					MoneyFrame_Update("A_MerchantItem"..i.."MoneyFrame", price);
					itemButton:Show();

					if ( numInStock == 0 ) then
						-- If not available and not usable
						if ( not isUsable ) then
							SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0, 0);
							SetItemButtonSlotVertexColor(merchantButton, 0.5, 0, 0);
							SetItemButtonTextureVertexColor(itemButton, 0.5, 0, 0);
							SetItemButtonNormalTextureVertexColor(itemButton, 0.5, 0, 0);
						else
							SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
							SetItemButtonSlotVertexColor(merchantButton, 0.5, 0.5, 0.5);
							SetItemButtonTextureVertexColor(itemButton, 0.5, 0.5, 0.5);
							SetItemButtonNormalTextureVertexColor(itemButton,0.5, 0.5, 0.5);
						end
					elseif ( inCart ) then
						SetItemButtonNameFrameVertexColor(merchantButton, 0, 1.0, 0);
						SetItemButtonSlotVertexColor(merchantButton, 0, 1.0, 0);
						SetItemButtonTextureVertexColor(itemButton, 0, 0.9, 0);
						SetItemButtonNormalTextureVertexColor(itemButton, 0, 0.9, 0);
					else
						SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
						SetItemButtonSlotVertexColor(merchantButton, 1.0, 1.0, 1.0);
						SetItemButtonTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
						SetItemButtonNormalTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
					end
				else
					SetItemButtonCount(itemButton, 0);
					SetItemButtonTexture(itemButton, "");
					SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
					SetItemButtonSlotVertexColor(merchantButton,0.4, 0.4, 0.4);
					SetItemButtonTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
					SetItemButtonNormalTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
					getglobal("A_MerchantItem"..i.."Name"):SetText("");
					getglobal("A_MerchantItem"..i.."MoneyFrame"):Hide();
				end
			end

			-- Handle featured item
			local FeaturedName, FeaturedTexture, FeaturedPrice, FeaturedCount, FeaturedNumAvailable, FeaturedInCart = MyS.stor.getItemInfo(0);

			if ( FeaturedInCart ) then
				A_MerchantFeaturedItemItemButton.locked = FeaturedInCart;
			else
				A_MerchantFeaturedItemItemButton.locked = nil;
			end

			if ( FeaturedName ) then
				if ( FeaturedInCart ) then
					SetItemButtonNameFrameVertexColor(A_MerchantFeaturedItem, 0, 1.0, 0);
					SetItemButtonSlotVertexColor(A_MerchantFeaturedItem, 0, 1.0, 0);
					SetItemButtonTextureVertexColor(A_MerchantFeaturedItemItemButton, 0, 0.9, 0);
					SetItemButtonNormalTextureVertexColor(A_MerchantFeaturedItemItemButton, 0, 0.9, 0);
				else
					SetItemButtonNameFrameVertexColor(A_MerchantFeaturedItem, 0.5, 0.5, 0.5);
					SetItemButtonSlotVertexColor(A_MerchantFeaturedItem, 1.0, 1.0, 1.0);
					SetItemButtonTextureVertexColor(A_MerchantFeaturedItemItemButton, 1.0, 1.0, 1.0);
					SetItemButtonNormalTextureVertexColor(A_MerchantFeaturedItemItemButton, 1.0, 1.0, 1.0);
				end
				SetItemButtonCount(A_MerchantFeaturedItemItemButton, FeaturedCount);
				SetItemButtonStock(A_MerchantFeaturedItemItemButton, FeaturedNumAvailable);
				SetItemButtonTexture(A_MerchantFeaturedItemItemButton, FeaturedTexture);
				A_MerchantFeaturedItemName:SetText(FeaturedName);
				A_MerchantFeaturedItemMoneyFrame:Show();
				MoneyFrame_Update("A_MerchantFeaturedItemMoneyFrame", FeaturedPrice);
				A_MerchantFeaturedItem:Show();
			else
				A_MerchantFeaturedItemName:SetText("No Featured Item");
				A_MerchantFeaturedItemMoneyFrame:Hide();
				SetItemButtonTexture(A_MerchantFeaturedItemItemButton, "");
				SetItemButtonCount(A_MerchantFeaturedItemItemButton, 0);
				SetItemButtonNameFrameVertexColor(A_MerchantFeaturedItem, 0.5, 0.5, 0.5);
				SetItemButtonTextureVertexColor(A_MerchantFeaturedItemItemButton, 1.0, 1.0, 1.0);
				SetItemButtonNormalTextureVertexColor(A_MerchantFeaturedItemItemButton, 1.0, 1.0, 1.0);
				SetItemButtonSlotVertexColor(A_MerchantFeaturedItem, 0.4, 0.4, 0.4);
				-- Hide the tooltip upon sale
				if ( GameTooltip:IsOwned(A_MerchantFeaturedItemItemButton) ) then
					GameTooltip:Hide();
				end
			end

			-- Handle paging buttons
			if ( highestMerchantItem >= MERCHANT_ITEMS_PER_PAGE ) then
				if ( MyS.stor.page == 1 ) then
					A_MerchantPrevPageButton:Disable();
				else
					A_MerchantPrevPageButton:Enable();
				end
				if ( MyS.stor.page == ceil((highestMerchantItem + 1) / MERCHANT_ITEMS_PER_PAGE) or highestMerchantItem == 0) then
					A_MerchantNextPageButton:Disable();
				else
					A_MerchantNextPageButton:Enable();
				end
				A_MerchantPageText:Show();
				A_MerchantPrevPageButton:Show();
				A_MerchantNextPageButton:Show();
			else
				A_MerchantPageText:Hide();
				A_MerchantPrevPageButton:Hide();
				A_MerchantNextPageButton:Hide();
			end
		end;

		prevButton_OnClick = function()
			PlaySound("igMainMenuOptionCheckBoxOn");
			MyS.stor.page = MyS.stor.page - 1;
			MyS.stor.refreshFrame();
		end;

		nextButton_OnClick = function()
			PlaySound("igMainMenuOptionCheckBoxOn");
			MyS.stor.page = MyS.stor.page + 1;
			MyS.stor.refreshFrame();
		end;

		refreshButtons = function()
			MyS.stor.MainButtons[4].refresh();
			MyS.stor.BottomBtn2.refresh();
		end;

		BottomBtn1 = {
			onClick = function()
				MyS.stor.goLive();
				MyS_AuxFunc.chatMessage("Changes saved...");
			end;

			onEnter = function()
				GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
				GameTooltip:SetText("Save items (Go Live)",1.0,1.0,1.0);
			end;
		};

		BottomBtn2 = {
			onLoad = function()
				this:RegisterForClicks("LeftButtonUp","RightButtonUp");
			end;

			onEnter = function()
				GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
				GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE.."Left-Click: "..FONT_COLOR_CODE_CLOSE.."Announce "..this:GetText().."\n"..HIGHLIGHT_FONT_COLOR_CODE.."Right-Click: "..FONT_COLOR_CODE_CLOSE.."Select announce type");
			end;

			refresh = function()
				local btnText = {
					[1] = "[Target]",
					[2] = "[Party]",
					[3] = "[Guild]",
					[4] = "[Trade]",
					[5] = "[Ask Me]"
				};
				A_MerchantBottomButton2:SetText(btnText[MyS_Session.user.announceType]);
			end;

			onClick = function(button)
				if ( button == "LeftButton" ) then
					if ( MyS_Session.user.announceType == 1 and not UnitExists("target") ) then
						MyS_AuxFunc.chatMessage("You don't have a target.");
					elseif ( MyS_Session.user.announceType == 2 and not GetPartyMember(1) ) then
						MyS_AuxFunc.chatMessage("You're not in a party.");
					elseif ( MyS_Session.user.announceType == 3 and not IsInGuild() ) then
						MyS_AuxFunc.chatMessage("You're not in a guild.");
					elseif ( MyS_Session.user.announceType == 4 and not MyS_Session.tradeChannel ) then
						MyS_AuxFunc.chatMessage("Trade channel does not exist.");
					elseif ( MyS_Session.user.announceType == 5 ) then
						StaticPopup_Show("MySERCH_TARGET");
					else
						MyS.stor.announce();
					end
				else
					ToggleDropDownMenu(1, nil, A_MerchantBottomButton2DropDown,this:GetName(), 0, 0);
				end
			end;

			dropdownClick = function(value)
				MyS_Session.user.announceType = value;
				MyS.stor.BottomBtn2.refresh();
			end;

			dropdownInit = function()
				local selectedValue = MyS_Session.user.announceType;
				local info;

				info = {};
				info.text = "Target";
				info.value = 1;
				info.func = function() MyS.stor.BottomBtn2.dropdownClick(1); end;
				if ( selectedValue == info.value ) then
					info.checked = 1;
				else
					info.checked = nil;
				end
				UIDropDownMenu_AddButton(info);

				info = {};
				info.text = "Party";
				info.value = 2;
				info.func = function() MyS.stor.BottomBtn2.dropdownClick(2); end;
				if ( selectedValue == info.value ) then
					info.checked = 1;
				else
					info.checked = nil;
				end
				UIDropDownMenu_AddButton(info);

				info = {};
				info.text = "Guild";
				info.value = 3;
				info.func = function() MyS.stor.BottomBtn2.dropdownClick(3); end;
				if ( selectedValue == info.value ) then
					info.checked = 1;
				else
					info.checked = nil;
				end
				UIDropDownMenu_AddButton(info);

				info = {};
				info.text = "Trade";
				info.value = 4;
				info.func = function() MyS.stor.BottomBtn2.dropdownClick(4); end;
				if ( selectedValue == info.value ) then
					info.checked = 1;
				else
					info.checked = nil;
				end
				UIDropDownMenu_AddButton(info);

				info = {};
				info.text = "Ask Me";
				info.value = 5;
				info.func = function() MyS.stor.BottomBtn2.dropdownClick(5); end;
				if ( selectedValue == info.value ) then
					info.checked = 1;
				else
					info.checked = nil;
				end
				UIDropDownMenu_AddButton(info);
			end;
		};

		MainButtons = {
			[1] = {
				onLoad = function()
					A_MerchantOptionButton1Icon:SetTexture("Interface\\Icons\\Spell_Frost_Stun");
				end;

				onEnter = function()
					GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
					GameTooltip:SetText("Refresh Clients",1.0,1.0,1.0);
				end;

				onClick = function()
					MyS.stor.refreshClients();
				end;
			};
			[2] = {
				onLoad = function()
					A_MerchantOptionButton2Icon:SetTexture("Interface\\Icons\\INV_Letter_05");
				end;

				onEnter = function()
					GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
					GameTooltip:SetText("Mail items to customers\n"..GRAY_FONT_COLOR_CODE.."(Not yet implimented)|r",1.0,1.0,1.0);
				end;

				onClick = function()
					-- Stuff
				end;
			};
			[3] = {
				onLoad = function()
					A_MerchantOptionButton3Icon:SetTexture("Interface\\Icons\\Spell_Nature_AbolishMagic");
				end;

				onEnter = function()
					GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
					GameTooltip:SetText("Clear All Items",1.0,1.0,1.0);
				end;

				onClick = function()
					MyS.stor.clearAllItems();
				end;
			};
			[4] = {
				refresh = function()
					-- Update store open / close status
					if ( MyS_Session.user.open and MyS_Session.user.open == 1 ) then
						-- Store is open
						A_MerchantOptionButton4Icon:SetTexture("Interface\\Icons\\Spell_Holy_DevotionAura");
						SetDesaturation(A_MerchantOptionButton4Icon,nil);
						A_MerchantOptionButton4.tooltip = "Store is OPEN";
					elseif ( MyS_Session.user.open and MyS_Session.user.open == 2 ) then
						-- Store is open for browsing and mail-order, but no auto-trades
						A_MerchantOptionButton4Icon:SetTexture("Interface\\Icons\\Spell_Holy_DevotionAura");
						SetDesaturation(A_MerchantOptionButton4Icon,1);
						A_MerchantOptionButton4.tooltip = "Store is open for Mail-Order";
					elseif ( not MyS_Session.user.open ) then
						A_MerchantOptionButton4Icon:SetTexture("Interface\\Icons\\Spell_Holy_BlessingOfProtection");
						SetDesaturation(A_MerchantOptionButton4Icon,nil);
						A_MerchantOptionButton4.tooltip = "Store is CLOSED";
					end
				end;

				onClick = function()
					-- Change store open / close status
					if ( MyS_Session.user.open and MyS_Session.user.open == 1 ) then
						MyS_Session.user.open = 2;
					elseif ( MyS_Session.user.open and MyS_Session.user.open == 2 ) then
						MyS_Session.user.open = nil;
					elseif ( not MyS_Session.user.open ) then
						MyS_Session.user.open = 1;
					end
					MyS.stor.MainButtons[4].refresh();
					MyS.stor.MainButtons[4].onEnter();

					for client, data in MyS_Session.currentClients do
						if ( data.password and data.active ) then
							MyS_AuxFunc.chatMessage("Sending status to "..client,1);
							MyS.stor.sendStatus(client);
						end
					end
				end;

				onEnter = function()
					if ( this.tooltip ) then
						GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
						GameTooltip:SetText(this.tooltip,1.0,1.0,1.0);
					end
				end;
			};
		};

		item = {
			onEnter = function()
				if ( not MyS.stor.getItemInfo(this:GetID()) ) then
					return;
				end
				local myLink = MyS_Session.tempStore[this:GetID()].link;
				local locked = this.locked;
				if ( myLink and strlen(myLink) > 0 ) then
					GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
					_,_,myLink = strfind(myLink,"|H(item:%d+:%d+:%d+:%d+)|");
					GameTooltip:SetHyperlink(myLink);
					if ( locked ) then
						GameTooltip:AddLine("(In "..locked.."'s Cart)", 0.75, 1.0, 0.75);
						GameTooltip:SetHeight(GameTooltip:GetHeight() + 14);
					end
				end
			end;

			onClick = function(featured)
				local button = this;
				local buttonName = this:GetName();
				local index;
				if ( featured ) then
					index = 0;
				else
					_,_,index = strfind(buttonName, "A_MerchantItem(%d+)ItemButton");
					index = ((MyS.stor.page - 1) * MERCHANT_ITEMS_PER_PAGE) + tonumber(index);
				end

				if ( CursorHasItem() ) then
					local bag = userCursorItem.bag;
					local slot = userCursorItem.slot;
					local price = userCursorItem.price;

					if ( not bag or not slot ) then return; end
					if ( userCursorItem.text2 == "Soulbound" ) then
						UIErrorsFrame:AddMessage(ERR_TRADE_BOUND_ITEM, 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME);
						return;
					elseif ( userCursorItem.text2 == "Quest Item" ) then
						UIErrorsFrame:AddMessage(ERR_TRADE_QUEST_ITEM, 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME);
						return;
					end

					MyS_Hook.containerItem(bag,slot);	-- Drop the item

					if ( MyS_Session.tempStore[index] ) then
						local oldBag = MyS_Session.tempStore[index].bag;
						local oldSlot = MyS_Session.tempStore[index].slot;
						local oldPrice = MyS_Session.tempStore[index].cost;
						MyS_Hook.containerItem(oldBag,oldSlot);
						userCursorItem.bag = oldBag;
						userCursorItem.slot = oldSlot;
						userCursorItem.price = oldPrice;
					else
						userCursorItem = nil;
					end

					MyS.stor.addItem(bag,slot,index,price);
				elseif ( MyS_Session.tempStore[index] and IsAltKeyDown() ) then
					MyS.stor.announce(index);
				elseif ( MyS_Session.tempStore[index] ) then
					local bag = MyS_Session.tempStore[index].bag;
					local slot = MyS_Session.tempStore[index].slot;
					local price = MyS_Session.tempStore[index].cost;
					MyS_Hook.containerItem(bag,slot);
					userCursorItem = {
						["bag"] = bag,
						["slot"] = slot,
						["price"] = price
					};
					MyS.stor.removeItem(index);
					if ( GameTooltip:IsOwned(this) ) then
						GameTooltip:Hide();
					end
				end
				MyS.stor.refreshFrame();

				for i = 1, NUM_CONTAINER_FRAMES, 1 do
					if ( getglobal("ContainerFrame" .. i):IsVisible() ) then
						ContainerFrame_Update(getglobal("ContainerFrame" .. i));
					end
				end
			end;
		};
	};

	trade = {
		addToCart = function(data,client)
			local _,_,id = strfind(data,"!ADD2CART!ITEMID!(%d+)");
			id = tonumber(id);
			local item = MyS_Session.user.saleItems[id];

			if ( item and item.bag and item.slot and (not MyS_Session.lockedItems[id] or MyS_Session.lockedItems[id] == client) ) then
				MyS_Session.currentClients[client]["cart"][id] = {
					["bag"] = item.bag,
					["slot"] = item.slot,
					["count"] = item.count,
					["cost"] = item.cost,
					["link"] = item.link
				};
				MyS_Session.lockedItems[id] = client;
				MyS_Comm.msgOut("!VRFYCART!ITEMID!"..id.."!SUCCESS!Q!"..item.quantity,client);
			else
				MyS_Comm.msgOut("!VRFYCART!ITEMID!"..id.."!FAIL!Q!0",client);
			end
			if ( A_MerchantFrame:IsVisible() ) then
				MyS.stor.refreshFrame();
			end
			MyS.stor.sendStatus(client);
		end;

		removeFromCart = function(id,client)
			local item = MyS_Session.user.saleItems[id];

			if ( item and item.bag and item.slot and MyS_Session.lockedItems[id] and MyS_Session.lockedItems[id] == client ) then
				MyS_Session.lockedItems[id] = nil;
			end
			MyS_Comm.msgOut("!VRFYCART!ITEMID!"..id.."!REMOVED!Q!"..item.quantity,client);
			MyS.stor.sendStatus(client);
		end;

		tradeItems = function()
			local unit = UnitName("NPC");

			if ( not MyS_Session.currentClients[unit] ) then return; end

			local cart = MyS_Session.currentClients[unit]["cart"];

			if ( cart ) then
				local cartPrice = 0;
				for index, val in cart do
					local slot = TradeFrame_GetAvailableSlot();
					local liveItem = MyS_Session.user.saleItems[index];
					if ( slot and val.bag and val.slot and MyS.stor.getItemInfo(index,1) and liveItem.count == val.count and liveItem.link == val.link and liveItem.cost == val.cost ) then
						MyS_Hook.containerItem(val.bag,val.slot);
						ClickTradeButton(slot);
						cartPrice = cartPrice + val.cost;
						val.inTrade = 1;
					else
						cart[index] = nil;
					end
				end
				if ( cartPrice > 0 ) then
					MyS_Comm.msgOut("!TRADETOTAL!"..cartPrice,unit);
				end
			end
		end;

		moneyChanged = function(arg1,arg2)
			local money = GetTargetTradeMoney();
			local unit = UnitName("NPC");

			if ( not MyS_Session.currentClients[unit] ) then return; end

			local cart = MyS_Session.currentClients[unit]["cart"];
			local cartPrice = 0;

			if ( cart ) then
				for index, val in cart do
					if ( val.inTrade ) then
						cartPrice = cartPrice + val.cost;
					end
				end
			end
			if ( cartPrice == money ) then
				AcceptTrade();
			end
		end;

		endTrade = function()
			local unit = UnitName("NPC");
			if ( not MyS_Session.currentClients[unit] ) then return; end

			local cart = MyS_Session.currentClients[unit]["cart"];

			for index, val in cart do
				local texture, count = GetContainerItemInfo(val.bag, val.slot);
				local link = GetContainerItemLink(val.bag,val.slot);
				if ( not link and val.inTrade ) then
					MyS.trade.removeFromCart(index,unit);
				elseif ( val.link == link and val.inTrade ) then
					val.inTrade = nil;
				end
			end
			MyS.stor.refreshClients();
		end;
	};
};

--[[	BEGIN PlayerComm functions ********************** ]]

MyS_Comm = {
	msgIn = function(arg1,arg2)
		if ( strfind(arg1,"!CUST!") ) then
			if ( strfind(arg1,"!SESSIONPASS!") ) then
				MyS.stor.saveClientPass(arg1,arg2);
			elseif ( strfind(arg1,"!OPENSTORE!") ) then
				MyS.stor.sendOpen(arg2);
			elseif ( strfind(arg1,"!REFRESH!") ) then
				MyS.stor.refreshClient(arg2);
			elseif ( strfind(arg1,"!BADPASS!") ) then
				MyS_AuxFunc.chatMessage("Handshake error with "..arg2.."...",1);
				MyS.stor.removeClient(arg2);
			elseif ( strfind(arg1,"!ADD2CART!") ) then
				MyS.trade.addToCart(arg1,arg2);
			elseif ( strfind(arg1,"!REMOVECART!") ) then
				local _,_,id = strfind(arg1,"!REMOVECART!ITEMID!(%d+)");
				MyS.trade.removeFromCart(tonumber(id),arg2);
			elseif ( strfind(arg1,"!CLOSESTORE!") ) then
				MyS.stor.removeClient(arg2);
			end
		elseif ( strfind(arg1,"!STOR!") ) then
			if ( strfind(arg1,"!OPENSTORE!") ) then
				MyS.cust.initStore(arg1,arg2);
			elseif ( not MyS.cust.currentStore or MyS.cust.currentStore ~= arg2 ) then
				MyS.cust.sendDeny(arg2);
			elseif ( strfind(arg1,"!REFRESH!") ) then
				MyS.cust.clearStore(arg2);
			elseif ( strfind(arg1,"!VRFYCART!") ) then
				MyS.cust.verifyCart(arg1,arg2);
			elseif ( strfind(arg1,"!ITEMID!") ) then
				MyS.cust.saveItem(arg1,arg2);
			elseif ( strfind(arg1,"!TOTALITEMS!") ) then
				MyS.cust.compareTotals(arg1,arg2);
			elseif ( strfind(arg1,"!STATUS!") ) then
				MyS.cust.setStatus(arg1,arg2);
			elseif ( strfind(arg1,"!TRADETOTAL!") ) then
				MyS.cust.showTradeCost(arg1,arg2);
			end
		elseif ( strfind(arg1,"(|c%x+|Hitem:%d+:%d+:%d+:%d+|h%[.+]|h|r)x(%d+)") and strfind(arg1,"(%d+)g(%d+)s(%d+)c") ) then
			MyS_AuxFunc.chatMessage(arg2.."'s Store announced.",1);
			MyS.storeList.add(arg1,arg2,1);
		else
			MyS_AuxFunc.chatMessage("Unhandled chat event: "..arg1.." - "..arg2,1);
		end
	end;

	msgOut = function(msg,who,customer)
		if ( msg and who and customer ) then
			MyS_Comm.queueMsg(who,"<MyStore>!CUST!"..msg);
		elseif ( msg and who ) then
			MyS_Comm.queueMsg(who,"<MyStore>!STOR!"..msg);
		end
	end;

	announce = function(msg,popTarget)
		local aType = MyS_Session.user.announceType;
		local chanList = {[2] = "Party",[3] = "Guild",[4] = "Trade"};

		if ( NEXT_ANNOUNCE_TIME[aType] and ((NEXT_ANNOUNCE_TIME[aType] + 10) < GetTime()) ) then
			if ( aType == 2 and GetPartyMember(1) ) then
				SendChatMessage(msg, "PARTY", DEFAULT_CHAT_FRAME.language);
				NEXT_ANNOUNCE_TIME[aType] = GetTime() + ANNOUNCE_INTERVAL;
			elseif ( aType == 3 and IsInGuild() ) then
				SendChatMessage(msg, "GUILD", DEFAULT_CHAT_FRAME.language);
				NEXT_ANNOUNCE_TIME[aType] = GetTime() + ANNOUNCE_INTERVAL;
			elseif ( aType == 4 and MyS_Session.tradeChannel ) then
				SendChatMessage(msg, "CHANNEL", DEFAULT_CHAT_FRAME.language, MyS_Session.tradeChannel);
				NEXT_ANNOUNCE_TIME[aType] = GetTime() + ANNOUNCE_INTERVAL;
			end			
		elseif ( NEXT_ANNOUNCE_TIME[aType] ) then
			MyS_AuxFunc.chatMessage("Time until next allowed "..chanList[aType].." announcement: "..((NEXT_ANNOUNCE_TIME[aType] + 10) - GetTime()).." seconds.");
		else
			if ( aType == 1 and UnitExists("target") and not UnitIsEnemy("target","player") and UnitIsPlayer("target") ) then
				SendChatMessage(msg, "WHISPER", DEFAULT_CHAT_FRAME.language, UnitName("target"));
			elseif ( popTarget and aType == 5 ) then
				SendChatMessage(msg, "WHISPER", DEFAULT_CHAT_FRAME.language, popTarget);
			end
		end
	end;

	publicMsgIn = function(arg1,arg2,channel)
		if ( strfind(arg1,"(|c%x+|Hitem:%d+:%d+:%d+:%d+|h%[.+]|h|r)x(%d+)") and strfind(arg1,"(%d+)g(%d+)s(%d+)c") ) then
			MyS.storeList.add(arg1,arg2,channel);
			return;
		end
	end;

	--[[ ********** Thanks to Iriel of Silver Hand for the following message-queueing code ]]
	COMMAND_QUEUE = {};		-- Table of player name to message queue table
	PLAYER_QUEUE = {};		-- Table which is list of player names

	queueMsg = function(player, message)
		local queue = MyS_Comm.COMMAND_QUEUE[player];
		if ( not queue ) then
			queue = { message };
			MyS_Comm.COMMAND_QUEUE[player] = queue;
			tinsert(MyS_Comm.PLAYER_QUEUE, player);
		else
			tinsert(queue, message);
		end
	end;

	getNextOutbound = function()
		if ( getn(MyS_Comm.PLAYER_QUEUE) == 0 ) then
			return;
		end
		local player = tremove(MyS_Comm.PLAYER_QUEUE, 1);
		local queue = MyS_Comm.COMMAND_QUEUE[player];
		local message = tremove(queue, 1);
		if ( getn(queue) == 0 ) then
			MyS_Comm.COMMAND_QUEUE[player] = nil;
		else
			tinsert(MyS_Comm.PLAYER_QUEUE, player);
		end
		return player, message;
	end;
};

--[[	BEGIN Session functions ************************* ]]

MyS_Session = {
	lockedItems = {};
	knownStores = {};
	advertisedStores = {};
	advertisedStoresIdx = {};
	currentClients = {};
	tempStore = {};
	forceChanUpdate = 1;
	tradeChannel = nil;

	initialize = function(force)
		local user = UnitName("player").." of "..GetCVar("realmName");
		if ( not MyS_Session.stats or force ) then
			MyS_Session.stats = {
				sales = 0, views = 0, money = 0,
			};
		end
		if ( not MyS_Config[user] ) then
			MyS_Config[user] = {
				saleItems = {};
				open = nil;
				showMonitor = nil;
				announceType = 5;
				debugmode = nil;
			};
		end
		MyS_Session.user = MyS_Config[user];
		MyS_Session.clientPass = UnitName("player")..floor(GetTime());
	end;

	checkChannels = function()
		if ( GetTime() < NEXT_CHAN_UPDATE ) then
			return;
		end
		if ( MyS_Session.forceChanUpdate ) then
			ListChannels();
		end
		NEXT_CHAN_UPDATE = GetTime() + 5;
	end;

	handleZone = function()
		MyS_Session.tradeChannel = nil;
		MyS_Session.forceChanUpdate = 1;
	end;
};

--[[	BEGIN Monitor functions *************************** ]]

MyS_Monitor = {
	onLoad = function()
		-- Nothing atm
	end;

	onEvent = function(event)
		MyS_AuxFunc.chatMessage("Monitor event: "..event,1);
	end;
};

--[[	BEGIN Map Button functions ************************ ]]

MyS_MapButton = {
	isMovable = nil;

	resetPos = function()
		P_MerchantMapButton:ClearAllPoints();
		if ( MG_MapButton ) then
			P_MerchantMapButton:SetPoint("RIGHT","MG_MapButton","LEFT",0,0);
		else
			P_MerchantMapButton:SetPoint("TOPLEFT","MinimapCluster","TOPLEFT",-2,-2);
		end
	end;

	moveToggle = function(force)
		if ( force or not MyS_MapButton.isMovable ) then
			MyS_MapButton.isMovable = 1;
		else
			MyS_MapButton.isMovable = nil;
		end
	end;

	onClick = function(button)
		if ( button == "LeftButton" ) then
			if ( MyStoreFrame:IsVisible() ) then
				MyStoreFrame:Hide();
			else
				MyStoreFrame:Show();
			end
		else
			if ( getn(MyS_Session.advertisedStores) > 0 ) then
				MyS.bgFrame.tabClick(2);
			else
				MyS.bgFrame.tabClick(1);
			end
			MyStoreFrame:Show();
		end
	end;

	onEnter = function()
		local tipText;
		if ( MyS_Session.user.open and MyS_Session.user.open == 1 ) then
			tipText = "Store is "..HIGHLIGHT_FONT_COLOR_CODE.."OPEN";
		elseif ( MyS_Session.user.open and MyS_Session.user.open == 2 ) then
			tipText = "Store is "..HIGHLIGHT_FONT_COLOR_CODE.."open for Mail-Order";
		elseif ( not MyS_Session.user.open ) then
			tipText = "Store is "..HIGHLIGHT_FONT_COLOR_CODE.."CLOSED";
		end

		tipText = tipText.."\n\n"..HIGHLIGHT_FONT_COLOR_CODE.."Left-Click: "..FONT_COLOR_CODE_CLOSE.."Show/Hide MyStore Admin\n"..HIGHLIGHT_FONT_COLOR_CODE.."Right-Click: "..FONT_COLOR_CODE_CLOSE.."List MyStore Stores";

		GameTooltip:SetOwner(this,"ANCHOR_LEFT");
		GameTooltip:SetText(tipText);
	end;

	onLeave = function()
		GameTooltip:Hide();
	end;
};

--[[	BEGIN Auxiliary functions ************************* ]]

MyS_AuxFunc = {
	getPos = function()
		--Player Coords ( from MapCoords Coded By ReCover )
		local px, py = GetPlayerMapPosition("player");
		px = floor(px * 100);
		py = floor(py * 100);

		return px,py,GetRealZoneText(),GetSubZoneText();
	end;

	getMoneyString = function(money)
		if ( not tonumber(money) ) then return; end

		-- Breakdown the money into denominations
		local gold = floor(money / (COPPER_PER_SILVER * SILVER_PER_GOLD));
		local silver = floor((money - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER);
		local copper = mod(money, COPPER_PER_SILVER);

		if ( gold == 0 ) then gold = "0";end
		if ( silver == 0 ) then silver = "0";end

		return gold.."g"..silver.."s"..copper.."c";
	end;

	getNameFromLink = function(link)
		if (link and string.find(link, "[", 1, true)) then
			local _,_,name = string.find(link, "^.*%[(.*)%].*$");
			return name;
		else
			return link;
		end
	end;

	chatMessage = function(msg,error)
		if( DEFAULT_CHAT_FRAME ) then
			if ( error and MyS_Session.user and MyS_Session.user.debugmode ) then
				DEFAULT_CHAT_FRAME:AddMessage("<MyStoreDebug> "..msg, 1.0, 0.5, 0.0);
			elseif ( not error ) then
				DEFAULT_CHAT_FRAME:AddMessage("<MyStore> "..msg, 1.0, 1.0, 0.0);
			end
		end
	end;

	getTrimText = function(s)
		return (string.gsub(s, "^%s*(.-)%s*$", "%1"));
	end;

	splitString = function(toCut, separator)
		local splitted = {};
		local i = 0;
		local regEx = "([^" .. separator .. "]*)" .. separator .. "?";

		for item in gfind(toCut .. separator, regEx) do
			i = i + 1;
			splitted[i] = MyS_AuxFunc.getTrimText(item) or '';
		end

		splitted[i] = nil;

		return splitted;
	end;

	copyTable = function(table, lookupTable)
		local copy = {};
		if ( not table ) then
			return {};
		end
		for key, val in table do
			if ( type(val) ~= "table" ) then
				copy[key] = val;
			else
				lookupTable = lookupTable or {};
				lookupTable[table] = copy;
				if ( lookupTable[val] ) then
					copy[key] = lookupTable[val];
				else
					copy[key] = MyS_AuxFunc.copyTable(val, lookupTable);
				end
			end
		end
		return copy;
	end;

	portraitOnEnter = function()
		local tipText = "MyStore "..MyS.version.."\n"..NORMAL_FONT_COLOR_CODE.."Author: jason.slaughter@gmail.com\nCurse Author-ID: 961"..FONT_COLOR_CODE_CLOSE;
		tipText = tipText.."\n\n|cff00ff00MyStore gives your customers\nan easy to use interface for browsing\nyour goods.  Simple yet effective!"..FONT_COLOR_CODE_CLOSE;

		GameTooltip_SetDefaultAnchor(GameTooltip, this);
		GameTooltip:SetText(tipText,1.0,1.0,1.0);
	end;
};

--[[	BEGIN Globals ************************************* ]]

StaticPopupDialogs["MySERCH_TARGET"] = {
	text = TEXT("Please enter the name you wish\nto announce your store to:"),
	button1 = TEXT(ACCEPT),
	button2 = TEXT(CANCEL),
	hasEditBox = 1,
	maxLetters = 32,
	OnAccept = function()
		local text = getglobal(this:GetParent():GetName().."EditBox"):GetText();
		MyS.stor.announce(nil,text);
	end,
	EditBoxOnEscapePressed = function ()
		this:GetParent():Hide();
	end,
	EditBoxOnEnterPressed = function()
		local text = getglobal(this:GetParent():GetName().."EditBox"):GetText();
		MyS.stor.announce(nil,text);
	end,
	OnShow = function()
		getglobal(this:GetName().."EditBox"):SetFocus();
	end,
	OnHide = function()
		if ( ChatFrameEditBox:IsVisible() ) then
			ChatFrameEditBox:SetFocus();
		end
		getglobal(this:GetName().."EditBox"):SetText("");
	end,
	timeout = 0,
	exclusive = 1
};
